package com.authine.cloudpivot.ext.controller.workflow;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.authine.cloudpivot.engine.api.model.organization.RoleModel;
import com.authine.cloudpivot.engine.api.model.organization.RoleUserModel;
import com.authine.cloudpivot.engine.api.model.organization.UserModel;
import com.authine.cloudpivot.engine.api.model.runtime.BizObjectModel;
import com.authine.cloudpivot.engine.api.model.runtime.BizObjectQueryModel;
import com.authine.cloudpivot.engine.api.model.runtime.SelectionValue;
import com.authine.cloudpivot.engine.api.model.runtime.WorkItemModel;
import com.authine.cloudpivot.engine.api.model.runtime.WorkflowInstanceModel;
import com.authine.cloudpivot.engine.component.query.api.FilterExpression;
import com.authine.cloudpivot.engine.component.query.api.Page;
import com.authine.cloudpivot.engine.enums.ErrCode;
import com.authine.cloudpivot.engine.enums.type.ProcessDataType;
import com.authine.cloudpivot.engine.enums.type.QueryDisplayType;
import com.authine.cloudpivot.ext.constant.UserConstants;
import com.authine.cloudpivot.ext.model.BaseModel;
import com.authine.cloudpivot.ext.model.SecretworkflowModel;
import com.authine.cloudpivot.web.api.controller.base.BaseController;
import com.authine.cloudpivot.web.api.dubbo.DubboConfigService;
import com.authine.cloudpivot.web.api.view.ResponseResult;
import com.google.common.collect.Maps;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * 二开流程相关接口
 *
 * @author shinka
 */
@Api(value = "流程相关接口", tags = "01::EXTAPI::二开流程相关接口")
@Controller
@RequestMapping("/public/ext/workflow")
public class ExtWorkFlowController extends BaseController {

    private static Logger log = LoggerFactory.getLogger(ExtWorkFlowController.class);

    private static final String THERE_ARE_OBJECTIONS = "有异议";

    @Autowired
    private DubboConfigService dubboConfigService;

    /**
     * 根据组织id查询流程参与者
     * 
     * @param params
     * @return
     */
    @ApiOperation(value = "根据组织id查询流程参与者")
    @PostMapping("/queryParticipant")
    @ResponseBody
    public String queryParticipant(@RequestBody Map<String, Object> params) {
        log.info("queryParticipant start params = {}", params);
        try {
            String roleCode = String.valueOf(params.get("roleCode"));
            // corpId实际上是部门ID，基于钉钉通讯录关联组织，下级组织在云枢里面实际上是部门
            String corpId = String.valueOf(params.get("corpId"));
            // 根据object查询表数据
            List<String> users = queryRoleUsers(roleCode, corpId);
            log.debug("根据组织编码查询参与者，接口返回内容：{}", users);
            List<String> resultList = new ArrayList<>();
            for (String s : users) {
                resultList.add("\"" + s + "\"");
            }
            // 解析返回结果
            String result = resultList.toString();
            // return getOkResponseResult(result, "根据组织编码查询参与者成功");
            return result;
        } catch (Exception e) {
            log.error("根据组织编码查询参与者失败：{}", e.toString());
            return "根据组织编码查询参与者失败";
        }
    }

    /**
     * 发起密报流程
     * 
     * @param params
     * @return
     */
    @ApiOperation(value = "发起密报流程")
    @PostMapping("/submitSecret")
    @ResponseBody
    public ResponseResult<String> submitSecret(@RequestBody Map<String, Object> params) {
        log.info("submitSecret start params = {}", params);
        Object villageSupervisionCommitteeOpinions = params.get("villageSupervisionCommitteeOpinions");
        if (!THERE_ARE_OBJECTIONS.equals(villageSupervisionCommitteeOpinions)) {
            return getOkResponseResult(String.valueOf(villageSupervisionCommitteeOpinions), ErrCode.OK.getErrMsg());
        }
        try {
            // 来源数据ID
            String sourceObjectId = String.valueOf(params.get("objectId"));
            // 来源模型编码
            String sourceSchemaCode = String.valueOf(params.get("schemaCode"));
            // 数据项编码
            String dataItemCode = String.valueOf(params.get("dataItemCode"));
            // 村监会流程审批节点编码
            String activityCode = String.valueOf(params.get("activityCode"));

            // 查询源表单数据
            Map<String, Object> dataMap = querySourceFormData(sourceObjectId, sourceSchemaCode);
            String workflowInstanceId = String.valueOf(dataMap.get(BaseModel.workflowInstanceId));
            String comments = String.valueOf(dataMap.get(SecretworkflowModel.LongText1622884890322));

            // 查询源表单流程节点数据（触发密报的节点）
            String participant = null;
            List<WorkItemModel> workItemList =
                dubboConfigService.getWorkflowInstanceFacade().getWorkItems(workflowInstanceId, true);
            if (CollectionUtils.isNotEmpty(workItemList)) {
                for (WorkItemModel workitemModel : workItemList) {
                    String code = workitemModel.getActivityCode();
                    if (code.equals(activityCode)) {
                        participant = workitemModel.getParticipant();
                        break;
                    }
                }
            }
            if (StringUtils.isEmpty(participant)) {
                // 获取user创建人
                participant = getUserId(null, dataMap, BaseModel.creater);
            }
            // 获取用户部门
            UserModel participantUser = dubboConfigService.getOrganizationFacade().getUser(participant);
            String participantDepartmentId = participantUser.getDepartmentId();
            String corpId = participantUser.getCorpId();

            // 查询村镇映射表
            final String vallgeCode = "ShortText1623401417630";// 村编码
            final String townCode = "town_dept_id";// 镇编码
            Map<String, Object> corpIdTownMappingMap = queryCorpIdTownMapping(corpId);
            JSONObject j = new JSONObject();
            j.put("id", corpIdTownMappingMap.get(townCode));
            j.put("type", 3);
            JSONArray townCodeDept = new JSONArray();
            townCodeDept.add(j);

            // 保存数据
            Map<String, Object> modelData = Maps.newHashMap();
            modelData.put(dataItemCode, sourceObjectId);
            modelData.put(SecretworkflowModel.LongText1622884890322, comments);
            modelData.put(SecretworkflowModel.corpId, corpIdTownMappingMap.get(vallgeCode));
            modelData.put(SecretworkflowModel.townId, townCodeDept);
            BizObjectModel model = new BizObjectModel(SecretworkflowModel.MODEL_SECRET, modelData, false);
            String thisFormObjectId = dubboConfigService.getBizObjectFacade().saveBizObject(participant, model, false);
            // 发起流程
            String result;
            result = dubboConfigService.getWorkflowInstanceFacade().startWorkflowInstance(participantDepartmentId,
                participant, SecretworkflowModel.MODEL_WORKFLOW_CODE, thisFormObjectId, false);
            return getOkResponseResult(result, "发起密报流程成功");
        } catch (Exception e) {
            log.error("发起密报流程失败：{}" + e);
            return getErrResponseResult(null, null, "发起密报流程失败：" + e.toString());
        }
    }

    @ApiOperation(value = "删除模拟流程数据，单条删除params:{\"schemaCode\": \"xxx\",\"objectId\": \"xxx\"}")
    @PostMapping("/deleteSimulativeById")
    @ResponseBody
    public ResponseResult<Object> deleteSimulativeById(@RequestBody Map<String, Object> params) {
        log.info("deleteSimulativeById start params = {}", params);
        try {
            String schemaCode = String.valueOf(params.get("schemaCode"));
            String objectId = String.valueOf(params.get("objectId"));
            String userId = this.getUserId();
            // if (StringUtils.isBlank(userId)) {
            // throw new Exception("userId can't be null.");
            // }
            if (StringUtils.isBlank(schemaCode)) {
                throw new Exception("schemaCode can't be null.");
            }
            if (StringUtils.isBlank(objectId)) {
                throw new Exception("objectId can't be null.");
            }

            boolean result = false;
            List<String> objectIdList = new ArrayList<>();
            objectIdList.add(objectId);
            List<WorkflowInstanceModel> workFlowList =
                dubboConfigService.getWorkflowInstanceFacade().getWorkflowInstancesByBizObjectId(objectIdList);
            if (CollectionUtils.isNotEmpty(workFlowList)) {
                for (int i = 0; i < workFlowList.size(); i++) {
                    WorkflowInstanceModel wm = workFlowList.get(i);
                    if (StringUtils.isBlank(userId)) {
                        userId = wm.getOriginator();
                        // removeBizObject方法userId无业务含义，避免方法参数校验失败，无userId时候以admin账号代替
                        if (StringUtils.isBlank(userId)) {
                            userId = UserConstants.USERID_ADMIN;
                        }
                    }
                    ProcessDataType dt = wm.getDataType();
                    if (ProcessDataType.SIMULATIVE.equals(dt)) {
                        result = dubboConfigService.getBizObjectFacade().removeBizObject(userId, schemaCode, objectId);
                        log.debug("删除模拟数据完成, result={}，userId={}", result, userId);
                    } else {
                        log.debug("非模拟数据不需要删除, workflowInstance={}", wm);
                    }
                }
            }
            return getOkResponseResult(result, "删除模拟流程数据成功");
        } catch (Exception e) {
            log.error("删除模拟流程数据失败：{}", e.toString());
            return getErrResponseResult(null, null, "删除模拟流程数据失败：" + e.toString());
        }
    }

    private List<String> queryRoleUsers(String roleCode, String deptId) {
        List<String> users = new ArrayList<>();
        // 根据角色编码查询角色
        RoleModel role = dubboConfigService.getOrganizationFacade().getRoleByCode(roleCode);
        String roleId = role.getId();
        if (StringUtils.isNotEmpty(roleId)) {
            // 根据角色id查询角色下面的用户
            List<RoleUserModel> roleUserList = dubboConfigService.getOrganizationFacade().getRoleUsersByRoleId(roleId);
            if (CollectionUtils.isNotEmpty(roleUserList)) {
                for (RoleUserModel roleUser : roleUserList) {
                    // 获取管理范围，管理范围包含传递的部门则返回用户ID
                    String ouScope = roleUser.getOuScope();
                    if (StringUtils.isNotEmpty(ouScope)) {
                        ouScope = ouScope.replace("[", "").replace("]", "").replaceAll("\"", "");
                        String[] arr = new String[] {ouScope};
                        if (ouScope.indexOf(",") > 0) {
                            arr = ouScope.split(",");
                        }
                        List<String> ouScopeList = Arrays.asList(arr);
                        if (ouScopeList.contains(deptId)) {
                            users.add(roleUser.getUserId());
                        }
                    }
                }
            } else {
                log.debug("根据角色ID查询数据为空：");
            }
        } else {
            log.debug("根据角色编码查询数据为空：");
        }
        return users;
    }

    @SuppressWarnings("unchecked")
    private String getUserId(String userId, Map<String, Object> dataMap, String key) {
        // 获取user创建人
        if (StringUtils.isBlank(userId) || "null".equals(userId)) {
            List<Map<String, Object>> createrMap = (List<Map<String, Object>>)dataMap.get(key);
            Map<String, Object> map = SelectionValue.toMap((SelectionValue)createrMap.get(0));
            userId = String.valueOf(map.get("id"));
        }
        return userId;
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> querySourceFormData(String objectId, String schemaCode) throws Exception {
        log.info("querySourceFormData start. params={}", objectId);
        if (StringUtils.isEmpty(objectId)) {
            log.error("查询结果异常,objectId为空");
            throw new Exception("查询结果异常,objectId为空");
        }

        List<String> columns = Lists.newArrayList();
        columns.add(SecretworkflowModel.LongText1622884890322);

        FilterExpression filter = new FilterExpression.Item(BaseModel.id, FilterExpression.Op.Eq, objectId);

        BizObjectQueryModel query = new BizObjectQueryModel();
        query.setSchemaCode(schemaCode);
        query.setQueryCode(schemaCode);
        query.setFilterExpr(filter);

        BizObjectQueryModel.Options options = new BizObjectQueryModel.Options();
        options.setQueryDisplayType(QueryDisplayType.APPEND);
        options.setCustomDisplayColumns(columns);
        query.setOptions(options);

        Page<BizObjectModel> resultPage = dubboConfigService.getBizObjectFacade().queryBizObjects(query);
        List<BizObjectModel> content = Lists.newArrayList();
        if (resultPage != null) {
            content = (List<BizObjectModel>)resultPage.getContent();
        }
        // 正常情况只会查询一条数据出来
        if (content.size() == 0 || content.size() > 1) {
            log.error("querySourceFormData error.", "查询结果异常,根据ID查询结果为空或大于1");
            throw new Exception("查询结果异常,根据ID查询结果为空或大于1");
        }

        log.info("querySourceFormData end.", "");
        return content.get(0).getData();
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> queryCorpIdTownMapping(String corpId) throws Exception {
        final String vallgeCode = "ShortText1623401417630";// 村编码
        final String townCode = "town_dept_id";// 镇编码
        final String orgCorpId = "ShortText1623401421367";
        final String schemaCode = "gjy";
        final String queryCode = "gjy";

        log.info("queryCorpIdTownMapping start. params={}", corpId);
        if (StringUtils.isEmpty(corpId)) {
            log.error("查询结果异常，用户表corpId为空");
            throw new Exception("查询结果异常，用户表corpId为空");
        }

        List<String> columns = Lists.newArrayList();
        columns.add(orgCorpId);
        columns.add(vallgeCode);
        columns.add(townCode);

        FilterExpression filter = new FilterExpression.Item(orgCorpId, FilterExpression.Op.Eq, corpId);

        BizObjectQueryModel.Options options = new BizObjectQueryModel.Options();
        options.setQueryDisplayType(QueryDisplayType.APPEND);
        options.setCustomDisplayColumns(columns);

        BizObjectQueryModel query = new BizObjectQueryModel();
        query.setOptions(options);
        query.setFilterExpr(filter);
        query.setSchemaCode(schemaCode);
        query.setQueryCode(queryCode);

        Page<BizObjectModel> resultPage = dubboConfigService.getBizObjectFacade().queryBizObjects(query);
        List<BizObjectModel> content = Lists.newArrayList();
        if (resultPage != null) {
            content = (List<BizObjectModel>)resultPage.getContent();
        }
        // 正常情况只会查询一条数据出来
        if (content.size() == 0 || content.size() > 1) {
            log.error("查询村镇映射表数据：查询结果异常,根据ID查询结果为空或大于1");
            throw new Exception("查询村镇映射表数据：查询结果异常,根据ID查询结果为空或大于1");
        }

        log.info("queryCorpIdTownMapping end.content={}", content);
        return content.get(0).getData();
    }
}
